package main.java.FSMDE.controllers;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.ParserConfigurationException;

import main.java.ERMDE.infrastructure.IFileSystemService;
import main.java.ERMDE.jgraph.extensions.CustomGraph;
import main.java.FSMDE.controllers.factories.IInterfaceControllerFactory;
import main.java.FSMDE.controllers.factories.ITransitionControllerFactory;
import main.java.FSMDE.controllers.listeners.IDiagramEventListener;
import main.java.FSMDE.infrastructure.IProjectContext;
import main.java.FSMDE.models.Diagram;
import main.java.FSMDE.models.Interface;
import main.java.FSMDE.models.Operations;
import main.java.FSMDE.models.Transition;
import main.java.FSMDE.models.TransitionControl;
import main.java.FSMDE.persistence.IGraphPersistenceService;
import main.java.FSMDE.persistence.IXmlManager;
import main.java.FSMDE.styling.StyleConstants;
import main.java.FSMDE.styling.Styler;
import main.java.FSMDE.validation.IProjectValidationService;
import main.java.FSMDE.views.IDiagramView;
import main.java.common.IXmlFileManager;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;


public class DiagramController extends BaseController implements
		IDiagramController, mxIEventListener {

	public static class CellConstants {
		public static final String InterfacePrefix = "Interface";
		public static final String TransitionPrefix = "Transition";
		public static final String ComponentPrefix = "Component";
		public static final String TransitionConnectorPrefix = "TransitionConnector";
		public static final String LegendPrefix = "Legend";
		public static final String TransitionDescriptionPrefix = "TranstionDescription";
	}

	private static final int zoomInOutMax = 5;
	private int zoomInOut;
	private Operations currentOperation;
	private Diagram diagram;
	private List<IDiagramEventListener> listeners;
	private Interface pendingInterface;
	private Transition pendingTransition;
	private CustomGraph graph;
	private IDiagramView diagramView;
	private IProjectValidationService validationService;
	private IFileSystemService fileSystemService;
	private IInterfaceControllerFactory interfaceControllerFactory;
	private ITransitionControllerFactory transitionControllerFactory;
	private HashMap<String, mxCell> interfaceCells;
	private HashMap<String, mxCell> transitionCells;
	private Map<String, mxCell> transitionConnectorCells;
	private IXmlFileManager xmlFileManager;
	private IXmlManager<Diagram> diagramXmlManager;
	private IGraphPersistenceService graphPersistenceService;
	private mxCell legendCell;
	private ArrayList<main.java.ERMDE.models.Diagram> ermDiagrams;
	private mxCell ultimateTransitionCell;

	public DiagramController(IProjectContext projectContext,
			IDiagramView diagramView,
			IInterfaceControllerFactory interfaceControllerFactory,
			ITransitionControllerFactory transitionControllerFactory,
			IXmlFileManager xmlFileManager,
			IXmlManager<Diagram> diagramXmlManager,
			IGraphPersistenceService graphPersistenceService,
			IProjectValidationService validationService,
			IFileSystemService fileSystemService) {

		super(projectContext);

		this.zoomInOut = 0;
		this.ultimateTransitionCell = null;
		this.validationService = validationService;
		this.fileSystemService = fileSystemService;
		this.currentOperation = Operations.None;
		this.diagram = new Diagram();
		this.interfaceControllerFactory = interfaceControllerFactory;
		this.transitionControllerFactory = transitionControllerFactory;
		this.graph = new CustomGraph();
		this.graph.setMaximumGraphBounds(new mxRectangle(10, 10, 2490, 3518)); // A4
																				// Size
																				// with
																				// a
																				// 10px
																				// padding
		this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this);

		this.interfaceCells = new HashMap<String, mxCell>();
		this.transitionCells = new HashMap<String, mxCell>();
		this.transitionConnectorCells = new HashMap<String, mxCell>();
		this.xmlFileManager = xmlFileManager;
		this.diagramXmlManager = diagramXmlManager;
		this.diagramView = diagramView;
		this.diagramView.setController(this);
		this.graphPersistenceService = graphPersistenceService;
		this.listeners = new ArrayList<IDiagramEventListener>();

		this.legendCell = null;

		ermDiagrams = new ArrayList<main.java.ERMDE.models.Diagram>();
	}

	@Override
	public void handleCreatedEvent(Interface interface0) {
		switch (this.currentOperation) {
		case Updating:
			this.handleInterfaceUpdate(interface0);
			this.diagram.isNotValidated();
			for (IDiagramEventListener listener : this.listeners) {
				listener.handleInterfaceUpdated(this.diagram, interface0);
			}
			break;
		case Creating:
		default:
			this.pendingInterface = interface0;
			break;
		}

		this.currentOperation = Operations.None;
	}

	private void handleInterfaceUpdate(Interface interface0) {
		this.graph.getModel().beginUpdate();
		try {
			mxCell interfaceCell = this.getInterfaceCell(interface0.getId()
					.toString());

			this.graph.getView().getState(interfaceCell).setLabel(interface0.getName());
			interfaceCell.setValue(interface0.getName());
			interfaceCell.setStyle(Styler.getFillColor(interface0.getType())
					+ ";"
					+ Styler.getStyle(interface0.getGraphType().toString(),
							interface0.hasSubDiagram()));
			// Update width and height
			double ratio = Styler.getSizeRatio(interface0.getName().length());
			mxGeometry actualGeom = interfaceCell.getGeometry();
			actualGeom.setHeight(ratio * StyleConstants.INTERFACE_HEIGHT);
			actualGeom.setWidth(ratio * StyleConstants.INTERFACE_WIDTH);
			interfaceCell.setGeometry(actualGeom);

			this.diagramView.refreshGraphComponent();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {

			for (Transition t : this.diagram.getTransitions()) {
				if (t instanceof TransitionControl) {
					if (((TransitionControl) t).getTriggerComponent() != null) {
						boolean eliminado = true;
						for (Interface i : this.diagram.getInterfaces()) {
							if (i.getComponent(((TransitionControl) t)
									.getTriggerComponent().getId().toString()) != null) {
								eliminado = false;
							}
						}
						if (eliminado) {
							((TransitionControl) t).setTriggerComponent(null);
							mxCell cell = this.transitionCells
									.get(CellConstants.TransitionPrefix
											+ t.getId().toString());
							graph.getModel().setValue(cell,
									t.getModelDescription());
							mxGeometry geometry = new mxGeometry(cell
									.getGeometry().getCenterX(), cell
									.getGeometry().getCenterY(),
									getTransitionCellWidth(t
											.getModelDescription()), cell
											.getGeometry().getHeight());
							graph.getModel().setGeometry(cell, geometry);
						}
					}
				}
			}
			this.graph.getModel().endUpdate();
			this.graph.repaint();
		}
	}

	@Override
	public void createInterface() {
		if (!this.hasPendingInterface()) {
			this.currentOperation = Operations.Creating;
			IInterfaceController interfaceController = this.interfaceControllerFactory
					.create();
			interfaceController.setErmDiagrams(ermDiagrams);
			interfaceController.addSubscriber(this);
			interfaceController.create();
		}
	}

	@Override
	public void addInterface(double x, double y) throws Exception {
		if (pendingInterface == null) {
			return;
		}

		this.graph.getModel().beginUpdate();
		Object parent = this.graph.getDefaultParent();
		try {
			this.addInterfaceToGraph(this.pendingInterface, parent, x, y);
		} finally {
			this.diagram.getInterfaces().add(this.pendingInterface);
			this.diagram.isNotValidated();
			for (IDiagramEventListener listener : this.listeners) {
				listener.handleInterfaceAdded(this.diagram,
						this.pendingInterface);
			}
			this.graph.getModel().endUpdate();
		}

		this.pendingInterface = null;
	}

	private mxCell addInterfaceToGraph(Interface interface0, Object parent,
			double x, double y) throws Exception {

		String style = Styler.getStyle(interface0.getGraphType().toString(),
				interface0.hasSubDiagram());

		double ratio = Styler.getSizeRatio(interface0.getName().length());

		mxCell interfaceCell = (mxCell) this.graph.insertVertex(parent,
				CellConstants.InterfacePrefix + interface0.getId().toString(),
				interface0.getName(), x, y, ratio
						* StyleConstants.INTERFACE_WIDTH, ratio
						* StyleConstants.INTERFACE_HEIGHT,
				Styler.getFillColor(interface0.getType()) + ";" + style);

		this.interfaceCells.put(CellConstants.InterfacePrefix
				+ interface0.getId().toString(), interfaceCell);

		return interfaceCell;
	}

	public Collection<mxCell> getAllInterfaceCells() {
		return this.interfaceCells.values();
	}

	@Override
	public mxCell getInterfaceCell(String id) {
		return this.interfaceCells.get(CellConstants.InterfacePrefix + id);
	}

	@Override
	public boolean hasPendingInterface() {
		return this.pendingInterface != null;
	}

	@Override
	public void updateInterface(Interface interface0) {
		this.currentOperation = Operations.Updating;

		IInterfaceController interfaceController = this.interfaceControllerFactory
				.create();
		interfaceController.setErmDiagrams(ermDiagrams);
		interfaceController.addSubscriber(this);
		interfaceController.create(interface0);
	}

	@Override
	public void updateTransition(Transition transition) {
		this.currentOperation = Operations.Updating;

		this.removeTransitionConnectors(transition);
		this.removeTransitionCells(transition);

		ITransitionController transitionController = this.transitionControllerFactory
				.create();
		transitionController.addSubscriber(this);
		transitionController.create(transition);

		this.graph.getModel().endUpdate();
		this.graph.repaint();
	}

	@Override
	public Iterable<Interface> getAvailableInterfaces() {
		return this.diagram.getInterfaces();
	}

	@Override
	public boolean deleteInterface(Interface interface0) {
		if (this.diagram.getInterfaces().get(interface0.getId()) == null) {
			this.diagramView.showDeleteDialog(
					"Interface '" + interface0.getName(),
					"' does not belong to the current diagram.", false);
			return false;
		}
		String subdiagramMessage = "";
		if (interface0.hasSubDiagram()) {
			subdiagramMessage = "\n(Beware that this interface is related with the Subdiagram: '"
					+ interface0.getRelatedSubdiagramName()
					+ "'.\nIf you delete the"
					+ " interface, you will be deleting the Subdiagram as well.)";

		}
		if (this.diagramView.showDeleteDialog(
				"Interface " + interface0.getName(), subdiagramMessage, true)) {
			this.removeInterface(interface0);
			this.diagram.isNotValidated();

			return true;
		}
		return false;
	}

	private void removeInterface(Interface interface0) {
		this.currentOperation = Operations.Updating;

		mxIGraphModel model = this.graph.getModel();

		String interfaceCell = CellConstants.InterfacePrefix
				+ interface0.getId().toString();
		model.remove(this.interfaceCells.remove(interfaceCell));

		this.diagram.getInterfaces().remove(interface0.getName());

		for (Transition relatedTransition : interface0.getTransitions()) {

			removeTransitionInterfaceConnector(relatedTransition, interface0);
			if (relatedTransition.getSource() == interface0) {
				relatedTransition.setSource(null);
			}
			if (relatedTransition.getDestination() == interface0) {
				relatedTransition.setDestination(null);
			}
		}
		this.diagramView.refreshGraphComponent();
	}

	@Override
	public void handleCreatedEvent(Transition transition) throws Exception {
		double[] coordinates = this.getTransitionNodeCoordinates(
				transition.getSource(), transition.getDestination());
		double x = coordinates[0];
		double y = coordinates[1];
		if (this.ultimateTransitionCell != null) {
			x = this.ultimateTransitionCell.getGeometry().getRectangle().x;
			y = this.ultimateTransitionCell.getGeometry().getRectangle().y;
			this.ultimateTransitionCell = null;
		}
		this.graph.getModel().beginUpdate();

		try {
			Object parent = this.graph.getDefaultParent();
			mxCell transitionCell = this.addTransitionToGraph(transition,
					parent, x, y);

			Map<UUID, Integer> interfaceCount = new HashMap<UUID, Integer>();

			int count = 0;
			if (transition.getSource() != null) {
				count++;
				interfaceCount.put(transition.getSource().getId(), count);
			}
			if (transition.getDestination() != null) {
				count++;
				interfaceCount.put(transition.getDestination().getId(), count);
			}

			if (transition.getSource() != null) {
				this.addTransitionConnectorToGraph(parent, transition,
						transitionCell, transition.getSource(), false);
			}
			if (transition.getDestination() != null) {
				this.addTransitionConnectorToGraph(parent, transition,
						transitionCell, transition.getDestination(), true);
			}

		} finally {
			this.diagram.isNotValidated();
			this.diagram.getTransitions().add(transition);
			if (this.currentOperation == Operations.Creating) {
				for (IDiagramEventListener eventListener : this.listeners) {
					eventListener.handleTransitionAdded(this.diagram,
							transition);
				}
			}
			this.graph.getModel().endUpdate();
		}

		this.currentOperation = Operations.None;

	}

	private mxCell addTransitionConnectorToGraph(Object parent,
			Transition transition, mxCell transitionCell,
			Interface transitionInterface, boolean isDestinationArrow) {
		boolean reflexive = (transition.getSource() != null)
				&& (transition.getDestination() != null)
				&& (transition.getSource().getId() == transition
						.getDestination().getId());

		String connectorId = transition.getId().toString()
				+ transitionInterface.getId().toString();

		if (reflexive && isDestinationArrow) {
			connectorId += "r";
		}
		mxCell interfaceCell = this.getInterfaceCell(transitionInterface
				.getId().toString());

		String transitionLinkStyle = StyleConstants.TRANSITION_LINK_STYLE_SOURCE;

		if (isDestinationArrow) {
			transitionLinkStyle = StyleConstants.TRANSITION_LINK_STYLE_DESTINATION;
			if (reflexive) {
				transitionLinkStyle += ";entryX=1;entryY=0.5;exitX=1;exitY=0.5;edgeStyle="
						+ mxConstants.EDGESTYLE_ORTHOGONAL + ";elbow=vertical;"; // entryPerimeter=1;
																					// ";edgeStyle=elbowEdgeStyle;elbow=horizontal;orthogonal=0;"
			}
		} else {
			if (reflexive) {
				transitionLinkStyle += ";entryX=0;entryY=0.5;exitX=0;exitY=0.5;entryPerimeter=1;exitPerimeter=1;edgeStyle="
						+ mxConstants.EDGESTYLE_ORTHOGONAL + ";elbow=vertical;";
			}
		}

		mxCell connectorCell = (mxCell) this.graph.insertEdge(parent,
				CellConstants.TransitionConnectorPrefix + connectorId, "",
				transitionCell, interfaceCell, transitionLinkStyle);

		this.transitionConnectorCells.put(
				CellConstants.TransitionConnectorPrefix + connectorId,
				connectorCell);

		return connectorCell;
	}

	private double[] getTransitionNodeCoordinates(Interface source,
			Interface destination) {

		double maxX = 0;
		double maxY = 0;
		double minY = Double.POSITIVE_INFINITY;
		double minX = Double.POSITIVE_INFINITY;

		if (source == null && destination == null) {
			return new double[] { -1, -1 };
		}
		if ((source != null || destination != null)
				&& (source == null || destination == null)) {
			Interface interface0 = null;
			if (source == null) {
				interface0 = destination;
			} else {
				interface0 = source;
			}

			mxCell interfaceCell = this.getInterfaceCell(interface0.getId()
					.toString());
			double x = interfaceCell.getGeometry().getX();
			double y = interfaceCell.getGeometry().getY();

			return new double[] { x, y + StyleConstants.INTERFACE_HEIGHT * 3 };
		}

		mxCell interfaceCell = this.getInterfaceCell(source.getId().toString());
		double x = interfaceCell.getGeometry().getX();
		double y = interfaceCell.getGeometry().getY();
		if (x > maxX) {
			maxX = x;
		}

		if (x < minX) {
			minX = x;
		}

		if (y > maxY) {
			maxY = y;
		}

		if (y < minY) {
			minY = y;
		}
		interfaceCell = this.getInterfaceCell(destination.getId().toString());
		x = interfaceCell.getGeometry().getX();
		y = interfaceCell.getGeometry().getY();
		if (x > maxX) {
			maxX = x;
		}

		if (x < minX) {
			minX = x;
		}

		if (y > maxY) {
			maxY = y;
		}

		if (y < minY) {
			minY = y;
		}

		double xPosition = minX + (maxX - minX) / 2;
		double yPosition = minY + (maxY - minY) / 2;

		return new double[] { xPosition, yPosition };
	}

	@Override
	public void createSubDiagram(String diagramName, String interfaceRelated) {

		this.setSubDiagramToInterface(interfaceRelated, diagramName);

		for (IDiagramEventListener listener : this.listeners) {
			listener.handleSubDiagramCreated(this.diagram, diagramName);
		}

		try {
			this.save();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}

	private void setSubDiagramToInterface(String interfaceRelated,
			String diagramName) {

		Iterator<Interface> itInterfaces = this.getAvailableInterfaces()
				.iterator();
		while (itInterfaces.hasNext()) {
			Interface iface = itInterfaces.next();

			if (iface.getName().equals(interfaceRelated)) {
				iface.setSubDiagram(diagramName);
				mxCell cell = this.interfaceCells
						.get(CellConstants.InterfacePrefix
								+ iface.getId().toString());
				graph.getModel().setStyle(cell,
						StyleConstants.INTERFACE_WITH_SUBDIAGRAM_STYLE);
			}
		}

	}

	@Override
	public void addListener(IDiagramEventListener listener) {
		this.listeners.add(listener);
	}

	public Iterator<IDiagramEventListener> getListeners() {
		return this.listeners.iterator();
	}

	@Override
	public mxGraph getGraph() {
		return this.graph;
	}

	@Override
	public Diagram getDiagram() {
		return diagram;
	}

	@Override
	public void createTransition() {
		if (!this.hasPendingTransition()) {
			this.currentOperation = Operations.Creating;
			ITransitionController transitionController = this.transitionControllerFactory
					.create();
			transitionController.addSubscriber(this);
			transitionController.create();
		}
	}

	@Override
	public void addTransition(double x, double y) throws Exception {
		if (pendingTransition == null) {
			return;
		}

		this.graph.getModel().beginUpdate();
		Object parent = this.graph.getDefaultParent();
		try {
			this.addTransitionToGraph(this.pendingTransition, parent, x, y);
		} finally {
			this.diagram.getTransitions().add(this.pendingTransition);
			this.diagram.isNotValidated();
			for (IDiagramEventListener listener : this.listeners) {
				listener.handleTransitionAdded(this.diagram,
						this.pendingTransition);
			}
			this.graph.getModel().endUpdate();
		}

		this.pendingTransition = null;
	}

	private mxCell addTransitionToGraph(Transition transition, Object parent,
			double x, double y) throws Exception {

		int width = getTransitionCellWidth(transition.getModelDescription());
		mxCell transitionCell = (mxCell) this.graph.insertVertex(parent,
				CellConstants.TransitionPrefix + transition.getId().toString(),
				transition.getModelDescription(), x, y, width,
				StyleConstants.TRANSITION_HEIGHT,
				Styler.getFillColor(transition.getType()) + ";"
						+ StyleConstants.TRANSITION_STYLE);

		this.transitionCells.put(CellConstants.TransitionPrefix
				+ transition.getId().toString(), transitionCell);

		return transitionCell;
	}

	private int getTransitionCellWidth(String modelDescription) {
		int width = 5;
		int upperCaseWidth = 6;
		for (int i = 0; i < modelDescription.length(); i++) {
			char c = modelDescription.charAt(i);
			if (Character.isUpperCase(c)) {
				width += upperCaseWidth;
			} else {
				switch (c) {
				case 'q':
				case 'e':
				case 'y':
				case 'u':
				case 'o':
				case 'p':
				case 'a':
				case 's':
				case 'd':
				case 'g':
				case 'h':
				case 'k':
				case 'z':
				case 'x':
				case 'c':
				case 'v':
				case 'b':
				case 'n': {
					width += 5;
					break;
				}
				case 'r':
				case 't':
				case 'f':
				case 'i': {
					width += 3;
					break;
				}
				case 'w': {
					width += 9;
					break;
				}
				case 'm': {
					width += 7;
					break;
				}
				default: {
					width += 4;
					break;
				}
				}
				width += 1;
			}
		}
		return width;
	}

	public mxCell getTransitionCell(String id) {
		return this.transitionCells.get(CellConstants.TransitionPrefix + id);
	}

	@Override
	public boolean hasPendingTransition() {
		return this.pendingTransition != null;
	}

	@Override
	public void save() throws ParserConfigurationException {
		Document document = this.xmlFileManager.createDocument();

		Element element = this.diagramXmlManager.getElementFromItem(
				this.diagram, document);

		document.appendChild(element);
		this.xmlFileManager.write(document, this.getComponentFilePath());

		this.graphPersistenceService.save(this.getRepresentationFilePath(),
				this.graph);
	}

	private String getRepresentationFilePath() {
		return this.projectContext.getDataDirectory() + "/"
				+ this.diagram.getName() + "-rep";
	}

	private String getComponentFilePath() {
		return this.projectContext.getDataDirectory() + "/"
				+ this.diagram.getName() + "-comp";
	}

	@Override
	public IDiagramView getView() {
		return diagramView;
	}

	@Override
	public void load(Diagram diagram) {
		this.diagram = diagram;
		String fileName = this.getRepresentationFilePath();
		this.graphPersistenceService.load(fileName, this.graph);

		Pattern regex1 = Pattern.compile(CellConstants.InterfacePrefix);
		Pattern regex2 = Pattern.compile(CellConstants.TransitionPrefix);
		Pattern regex3 = Pattern
				.compile(CellConstants.TransitionConnectorPrefix);
		for (Object o : this.graph.getChildCells(this.graph.getDefaultParent())) {
			mxCell cell = (mxCell) o;

			Matcher matcher = regex1.matcher(cell.getId());
			boolean matchFound = matcher.find();
			if (matchFound) {
				this.interfaceCells.put(cell.getId(), cell);
				continue;
			}
			matcher = regex3.matcher(cell.getId());
			matchFound = matcher.find();
			if (matchFound) {
				this.transitionConnectorCells.put(cell.getId(), cell);
				continue;
			}
			matcher = regex2.matcher(cell.getId());
			matchFound = matcher.find();
			if (matchFound) {
				this.transitionCells.put(cell.getId(), cell);
				continue;
			}
		}
	}

	@Override
	public String getDataDirectory() {
		return this.projectContext.getDataDirectory() + "/";
	}

	private void removeTransitionCells(Transition transition) {

		String keyConnector = CellConstants.TransitionPrefix
				+ transition.getId().toString();
		mxCell cell = this.transitionCells.remove(keyConnector);
		if (this.currentOperation == Operations.Updating) {
			this.ultimateTransitionCell = cell;
		} else {
			this.ultimateTransitionCell = null;
		}
		this.graph.getModel().remove(cell);
		this.diagram.getTransitions().remove(transition.getName());
	}

	private void removeTransitionConnectors(Transition transition) {
		if (transition.getSource() != null)
			removeTransitionInterfaceConnector(transition,
					transition.getSource());
		if (transition.getDestination() != null)
			removeTransitionInterfaceConnector(transition,
					transition.getDestination());
	}

	private void removeTransitionInterfaceConnector(Transition transition,
			Interface interface0) {

		boolean reflexive = (transition.getSource() != null)
				&& (transition.getDestination() != null)
				&& (transition.getSource().getId() == transition
						.getDestination().getId());

		mxIGraphModel model = this.graph.getModel();

		String transitionConnectorCell = CellConstants.TransitionConnectorPrefix
				+ transition.getId().toString() + interface0.getId().toString();

		model.remove(this.transitionConnectorCells
				.remove(transitionConnectorCell));
		if (reflexive)
			model.remove(this.transitionConnectorCells
					.remove(transitionConnectorCell + "r"));
	}

	@Override
	public boolean deleteTransition(Transition transition) {
		if (this.diagram.getTransitions().get(transition.getId()) == null) {
			this.diagramView.showDeleteDialog(
					"Transition " + transition.getName(),
					" don't belong into current diagram", false);
			return false;
		}
		if (this.diagramView.showDeleteDialog(
				"Transtion " + transition.getName(), "", true)) {
			this.removeTransition(transition);
			this.diagram.isNotValidated();
			return true;
		}

		return false;
	}

	private void removeTransition(Transition transition) {
		this.currentOperation = Operations.Updating;

		this.removeTransitionCells(transition);
		this.removeTransitionConnectors(transition);

		this.diagram.getTransitions().remove(transition.getName());

		this.diagramView.refreshGraphComponent();
	}

	@Override
	public void validate() {
		String reportHtml = this.validationService
				.generateIndividualReport(diagram);
		Date date = Calendar.getInstance().getTime();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		String reportName = this.projectContext.getDataDirectory() + "/"
				+ diagram.getName() + "_" + sdf.format(date)
				+ "_validationReport.html";
		this.fileSystemService.save(reportName, reportHtml);
		Desktop desktop = Desktop.getDesktop();
		try {
			desktop.open(new File(reportName));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void openDiagram(String path) throws Exception {
		Document document = this.xmlFileManager.read(path);
		Element element = document.getDocumentElement();
		this.diagram = this.diagramXmlManager.getItemFromXmlElement(element);
	}

	public mxCell getTransitionConnectorCell(String id) {
		return this.transitionConnectorCells
				.get(CellConstants.TransitionConnectorPrefix + id);
	}

	@Override
	public void toggleLegend() {
		this.graph.getModel().beginUpdate();
		try {
			if (this.legendCell == null) {
				Object parent = this.graph.getDefaultParent();
				this.legendCell = (mxCell) this.graph.insertVertex(parent,
						CellConstants.LegendPrefix, "", 0, 0,
						StyleConstants.LEGEND_WIDTH,
						StyleConstants.LEGEND_HEIGHT,
						StyleConstants.LEGEND_STYLE);
			} else {
				this.graph.getModel().remove(this.legendCell);
				this.legendCell = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			this.graph.getModel().endUpdate();
		}
	}

	@Override
	public void hideLegend() {
		this.graph.getModel().beginUpdate();
		try {
			if (this.legendCell != null) {
				this.graph.getModel().remove(this.legendCell);
				this.legendCell = null;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			this.graph.getModel().endUpdate();
		}
	}

	@Override
	public int getInterfacesCount() {
		return this.interfaceCells.size();
	}

	@Override
	public void addErmDiagrams(List<main.java.ERMDE.models.Diagram> diagrams) {
		this.ermDiagrams.clear();
		this.ermDiagrams.addAll(diagrams);
	}

	@Override
	public void refreshComponents() {
		for (Interface iface : this.getAvailableInterfaces()) {
			this.handleInterfaceUpdate(iface);
		}

	}

	@Override
	public Diagram getSubDiagram(String subdiagramName) {
		Diagram subdiagramWanted = null;
		for (Diagram sub : this.diagram.getSubDiagrams()) {
			if (sub.getName().equals(subdiagramName)) {
				subdiagramWanted = sub;
			}
		}
		return subdiagramWanted;
	}

	@Override
	public int getInterfacesAvailableForSubdiagramCount() {
		int count = 0;
		for (Interface iface : this.getAvailableInterfaces()) {
			if (!iface.hasSubDiagram()) {
				count++;
			}
		}
		return count;
	}

	@Override
	public boolean canDoZoomIn() {
		if (this.zoomInOut < zoomInOutMax) {
			return true;
		}
		return false;
	}

	@Override
	public void didZoomIn() {
		this.zoomInOut++;
	}

	@Override
	public boolean canDoZoomOut() {
		if (this.zoomInOut > -zoomInOutMax) {
			return true;
		}
		return false;
	}

	@Override
	public void didZoomOut() {
		this.zoomInOut--;
	}

	@Override
	public void invoke(Object arg0, mxEventObject arg1) {

	}
	
	@Override
	public void removeListener() {
	   this.listeners.clear();
	}

}
